<style scoped>
	.v-select {
		position: relative;
		font-family: sans-serif;
	}

	.v-select,
	.v-select * {
		-webkit-box-sizing: border-box;
		-moz-box-sizing: border-box;
		box-sizing: border-box;
	}

	/* Open Indicator */
	.v-select .open-indicator {
		position: absolute;
		bottom: 6px;
		right: 10px;
		display: inline-block;
		cursor: pointer;
		pointer-events: all;
		transition: all 150ms cubic-bezier(1.000, -0.115, 0.975, 0.855);
		transition-timing-function: cubic-bezier(1.000, -0.115, 0.975, 0.855);
		opacity: 1;
		transition: opacity .1s;
		height: 20px;
		width: 10px;
	}

	.v-select .open-indicator:before {
		border-color: rgba(60, 60, 60, .5);
		border-style: solid;
		border-width: 3px 3px 0 0;
		content: '';
		display: inline-block;
		height: 10px;
		width: 10px;
		vertical-align: top;
		transform: rotate(133deg);
		transition: all 150ms cubic-bezier(1.000, -0.115, 0.975, 0.855);
		transition-timing-function: cubic-bezier(1.000, -0.115, 0.975, 0.855);
		box-sizing: inherit;
	}

	/* Open Indicator States */
	.v-select.open .open-indicator:before {
		transform: rotate(315deg);
	}

	.v-select.loading .open-indicator {
		opacity: 0;
	}

	.v-select.open .open-indicator {
		bottom: 1px;
	}

	/* Dropdown Toggle */
	.v-select .dropdown-toggle {
		-webkit-appearance: none;
		-moz-appearance: none;
		appearance: none;
		display: block;
		padding: 0;
		background: none;
		border: 1px solid rgba(60, 60, 60, .26);
		border-radius: 4px;
		white-space: normal;
		transition: border-radius .25s;
	}

	.v-select .dropdown-toggle:after {
		visibility: hidden;
		display: block;
		font-size: 0;
		content: " ";
		clear: both;
		height: 0;
	}

	/* Dropdown Toggle States */
	.v-select.searchable .dropdown-toggle {
		cursor: text;
	}

	.v-select.unsearchable .dropdown-toggle {
		cursor: pointer;
	}

	.v-select.open .dropdown-toggle {
		border-bottom-color: transparent;
		border-bottom-left-radius: 0;
		border-bottom-right-radius: 0;
	}

	/* Dropdown Menu */
	.v-select .dropdown-menu {
		display: block;
		position: absolute;
		top: 100%;
		left: 0;
		z-index: 1000;
		min-width: 160px;
		padding: 5px 0;
		margin: 0;
		width: 100%;
		overflow-y: scroll;
		border: 1px solid rgba(0, 0, 0, .26);
		box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, .15);
		border-top: none;
		border-radius: 0 0 4px 4px;
		text-align: left;
		list-style: none;
		background: #fff;
	}

	.v-select .no-options {
		text-align: center;
	}

	/* Selected Tags */
	.v-select .selected-tag {
		color: #333;
		height: 26px;
		margin: 4px 1px 0px 3px;
		padding: 1px 0.25em;
		float: left;
		line-height: 24px;
		background-color: #f0f0f0;
		border: 1px solid #ccc;
	}

	.v-select .selected-tag .close {
		float: none;
		margin-right: 0;
		font-size: 20px;
		appearance: none;
		padding: 0;
		cursor: pointer;
		background: 0 0;
		border: 0;
		font-weight: 700;
		line-height: 1;
		color: #000;
		text-shadow: 0 1px 0 #fff;
		filter: alpha(opacity=20);
		opacity: .2;
	}

	/* Search Input */
	.v-select input[type="search"]::-webkit-search-decoration,
	.v-select input[type="search"]::-webkit-search-cancel-button,
	.v-select input[type="search"]::-webkit-search-results-button,
	.v-select input[type="search"]::-webkit-search-results-decoration {
		display: none;
	}

	.v-select input[type="search"]::-ms-clear {
		display: none;
	}

	.v-select input[type="search"],
	.v-select input[type="search"]:focus {
		appearance: none;
		-webkit-appearance: none;
		-moz-appearance: none;
		line-height: 1.42857143;
		font-size: 1em;
		height: 34px;
		display: inline-block;
		border: none;
		outline: none;
		margin: 0;
		padding: 0 .5em;
		width: 10em;
		max-width: 100%;
		background: none;
		position: relative;
		box-shadow: none;
		float: left;
		clear: none;
	}

	/* Search Input States */
	.v-select.unsearchable input[type="search"] {
		max-width: 1px;
	}

	/* List Items */
	.v-select li {
		line-height: 1.42857143; /* Normalize line height */
	}

	.v-select li > a {
		display: block;
		padding: 3px 20px;
		clear: both;
		color: #333; /* Overrides most CSS frameworks */
		white-space: nowrap;
	}

	.v-select li:hover {
		cursor: pointer;
	}

	.v-select .dropdown-menu .active > a {
		color: #333;
		background: rgba(50, 50, 50, .1);
	}

	.v-select .dropdown-menu > .highlight > a {
		/*
		 * required to override bootstrap 3's
		 * .dropdown-menu > li > a:hover {} styles
		 */
		background: #5897fb;
		color: #fff;
	}

	.v-select .highlight:not(:last-child) {
		margin-bottom: 0; /* Fixes Bulma Margin */
	}

	/* Loading Spinner */
	.v-select .spinner {
		opacity: 0;
		position: absolute;
		top: 5px;
		right: 10px;
		font-size: 5px;
		text-indent: -9999em;
		overflow: hidden;
		border-top: .9em solid rgba(100, 100, 100, .1);
		border-right: .9em solid rgba(100, 100, 100, .1);
		border-bottom: .9em solid rgba(100, 100, 100, .1);
		border-left: .9em solid rgba(60, 60, 60, .45);
		transform: translateZ(0);
		animation: vSelectSpinner 1.1s infinite linear;
		transition: opacity .1s;
	}

	.v-select .spinner,
	.v-select .spinner:after {
		border-radius: 50%;
		width: 5em;
		height: 5em;
	}

	/* Loading Spinner States */
	.v-select.loading .spinner {
		opacity: 1;
	}

	/* KeyFrames */
	@-webkit-keyframes vSelectSpinner {
		0% {
			transform: rotate(0deg);
		}
		100% {
			transform: rotate(360deg);
		}
	}

	@keyframes vSelectSpinner {
		0% {
			transform: rotate(0deg);
		}
		100% {
			transform: rotate(360deg);
		}
	}

	/* Dropdown Default Transition */
	.fade-enter-active,
	.fade-leave-active {
		transition: opacity .15s cubic-bezier(1.0, 0.5, 0.8, 1.0);
	}

	.fade-enter,
	.fade-leave-to {
		opacity: 0;
	}
</style>

<template>
	<div class="dropdown v-select" :class="dropdownClasses">
		<div ref="toggle" @mousedown.prevent="toggleDropdown" class="dropdown-toggle">
            <span class="selected-tag" v-if="!multiple" v-for="option in valueAsArray" v-bind:key="option.index">
                {{ getOptionLabel(option) }}
                <button v-if="multiple" @click="deselect(option)" type="button" class="close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </span>
			<span class="selected-tag" v-if="(!(valueAsArray.length === options.length)) && multiple"
				  v-for="option in valueAsArray" v-bind:key="option.index"> {{ getOptionLabel(option) }}
                <button @click="deselect(option)" type="button" class="close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </span>
			<span class="selected-tag"
				  v-if="allSel && (valueAsArray.length === options.length) && multiple">{{ 'All Selected' }}
                <button @click="deselectAll()" type="button" class="close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </span>
			<span class="selected-tag" v-if="!allSel && (valueAsArray.length === options.length) && multiple"
				  v-for="option in valueAsArray" v-bind:key="option.index">{{ getOptionLabel(option) }}
                <button @click="deselect(option)" type="button" class="close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </span>
			<input
					ref="search"
					v-model="search"
					@keydown.delete="maybeDeleteValue"
					@keyup.esc="onEscape"
					@keydown.up.prevent="typeAheadUp"
					@keydown.down.prevent="typeAheadDown"
					@keyup.enter.prevent="typeAheadSelect"
					@blur="onSearchBlur"
					@focus="onSearchFocus"
					type="search"
					class="form-control"
					:placeholder="searchPlaceholder"
					:readonly="!searchable"
					:style="{ width: isValueEmpty ? '100%' : 'auto', color: '#666' }"
					:id="inputId">
			<i v-if="!noDrop" ref="openIndicator" role="presentation" class="open-indicator"></i>
			<slot name="spinner">
				<div class="spinner" v-show="mutableLoading">Loading...</div>
			</slot>
		</div>

		<transition :name="transition">
			<ul ref="dropdownMenu" v-if="dropdownOpen" class="dropdown-menu" :style="{ 'max-height': maxHeight }">
				<li v-if="multiple && allSel">
					<a @mousedown.prevent="toggleAll">
						{{ valueAsArray.length === options.length ? '取消' : '' }}选择全部
					</a>
				</li>
				<hr v-if="multiple && allSel"/>
				<li v-for="(option, index) in filteredOptions" v-bind:key="index"
					:class="{ active: isOptionSelected(option), highlight: index === typeAheadPointer }"
					@mouseover="typeAheadPointer = index">
					<a @mousedown.prevent="select(option)">
						{{ getOptionLabel(option) }}
					</a>
				</li>
				<li v-if="!filteredOptions.length" class="no-options">
					<slot name="no-options">没有可选择.</slot>
				</li>
			</ul>
		</transition>
	</div>
</template>

<script>
	export default {
		props: {
			value: {default: null},
			options: {type: Array, default () { return []; }},
			allSel: {type: Boolean, default: true},
			maxHeight: {type: String, default: '400px'},
			searchable: {type: Boolean, default: true},
			multiple: {type: Boolean, default: false},
			placeholder: {type: String, default: ''},
			transition: {type: String, default: 'fade'},
			clearSearchOnSelect: {type: Boolean, default: true},
			label: {type: String, default: 'label'},
			getOptionLabel: {
				type: Function,
				default: (option) => {
					if (typeof option === 'object') {
						if (this.label && option[this.label]) {
							return option[this.label];
						}
					}
					return option;
				}
			},
			onChange: {
				type: Function,
				default: (val) => {
					this.$emit('input', val);
				}
			},
			taggable: {type: Boolean, default: false},
			pushTags: {type: Boolean, default: false},
			/**
			 * User defined function for adding Options
			 * @type {Function}
			 */
			createOption: {
				type: Function,
				default: (newOption) => {
					if (typeof this.mutableOptions[0] === 'object') {
						newOption = {[this.label]: newOption};
					}
					this.$emit('option:created', newOption);
					return newOption;
				}
			},
			resetOnOptionsChange: {
				type: Boolean,
				default: false
			},
			noDrop: {
				type: Boolean,
				default: false
			},
			inputId: {
				type: String
			}
		},
		data () {
			return {
				search: '',
				open: false,
				mutableValue: null,
				mutableOptions: []
			};
		},
		watch: {
			value (val) {
				this.mutableValue = val;
			},
			mutableValue (val, old) {
				if (this.multiple) {
					this.onChange ? this.onChange(val) : null;
				} else {
					this.onChange && val !== old ? this.onChange(val) : null;
				}
			},
			options (val) {
				this.mutableOptions = val;
			},
			mutableOptions () {
				if (!this.taggable && this.resetOnOptionsChange) {
					this.mutableValue = this.multiple ? [] : null;
				}
			},
			multiple (val) {
				this.mutableValue = val ? [] : null;
			}
		},
		created () {
			this.mutableValue = this.value;
			this.mutableOptions = this.options.slice(0);
			this.mutableLoading = this.loading;
			this.$on('option:created', this.maybePushTag);
			if (!this.multiple) {
				if (this.mutableOptions && this.mutableOptions.length > 0) {
					this.mutableValue = this.mutableOptions.slice(0)[0];
				}
			}
		},
		methods: {
			select (option) {
				if (this.isOptionSelected(option) && this.multiple) {
					this.deselect(option);
				} else {
					if (this.taggable && !this.optionExists(option)) {
						option = this.createOption(option);
					}
					if (this.multiple && !this.mutableValue) {
						this.mutableValue = [option];
					} else if (this.multiple) {
						this.mutableValue.push(option);
					} else {
						this.mutableValue = option;
					}
				}
				this.onAfterSelect(option);
			},
			selectAll () {
				if (this.multiple) {
					this.mutableValue = this.mutableOptions.slice(0);
				} else {
					this.mutableValue = this.mutableOptions.slice(0)[0];
				}
			},
			deselect (option) {
				if (this.multiple) {
					let ref = -1;
					this.mutableValue.forEach((val) => {
						if (val === option || typeof val === 'object' && val[this.label] === option[this.label]) {
							ref = val;
						}
					});
					var index = this.mutableValue.indexOf(ref);
					this.mutableValue.splice(index, 1);
				} else {
					this.mutableValue = null;
				}
			},
			deselectAll () {
				if (this.multiple) {
					this.mutableValue = [];
				} else {
					this.mutableValue = null;
				}
			},
			toggleAll () {
				if (this.valueAsArray.length === this.mutableOptions.length) {
					this.deselectAll();
				} else {
					this.selectAll();
				}
			},
			onAfterSelect (option) {
				if (!this.multiple) {
					this.open = !this.open;
					this.$refs.search.blur();
				}
				if (this.clearSearchOnSelect) {
					this.search = '';
				}
			},
			toggleDropdown (e) {
				if (e.target === this.$refs.openIndicator || e.target === this.$refs.search || e.target === this.$refs.toggle || e.target === this.$el) {
					if (this.open) {
						this.$refs.search.blur(); // dropdown will close on blur
					} else {
						this.open = true;
						this.$refs.search.focus();
					}
				}
			},
			isOptionSelected (option) {
				if (this.multiple && this.mutableValue) {
					let selected = false;
					this.mutableValue.forEach(opt => {
						if (typeof opt === 'object' && opt[this.label] === option[this.label]) {
							selected = true;
						} else if (typeof opt === 'object' && opt[this.label] === option) {
							selected = true;
						} else if (opt === option) {
							selected = true;
						}
					});
					return selected;
				}
				return this.mutableValue === option;
			},
			onEscape () {
				if (!this.search.length) {
					this.$refs.search.blur();
				} else {
					this.search = '';
				}
			},
			onSearchBlur () {
				this.open = false;
				this.$emit('search:blur');
			},
			onSearchFocus () {
				this.open = true;
				this.$emit('search:focus');
			},
			maybeDeleteValue () {
				if (!this.$refs.search.value.length && this.mutableValue) {
					let r = this.multiple ? this.mutableValue.pop() : this.mutableValue = null;
					return r;
				}
			},
			optionExists (option) {
				let exists = false;
				this.mutableOptions.forEach(opt => {
					if (typeof opt === 'object' && opt[this.label] === option) {
						exists = true;
					} else if (opt === option) {
						exists = true;
					}
				});
				return exists;
			},
			maybePushTag (option) {
				if (this.pushTags) {
					this.mutableOptions.push(option);
				}
			}
		},
		computed: {
			dropdownClasses () {
				return {
					open: this.dropdownOpen,
					searchable: this.searchable,
					unsearchable: !this.searchable,
					loading: this.mutableLoading
				};
			},
			dropdownOpen () {
				return this.noDrop ? false : this.open && !this.mutableLoading;
			},
			searchPlaceholder () {
				if (this.isValueEmpty && this.placeholder) {
					return this.placeholder;
				}
			},
			filteredOptions () {
				let options = this.mutableOptions.filter((option) => {
					if (typeof option === 'object' && option.hasOwnProperty(this.label)) {
						return option[this.label].toLowerCase().indexOf(this.search.toLowerCase()) > -1;
					} else if (typeof option === 'object' && !option.hasOwnProperty(this.label)) {
						return console.warn(`[vue-select warn]: Label key "option.${this.label}" does not exist in options object.\nhttp://sagalbot.github.io/vue-select/#ex-labels`);
					}
					return option.toLowerCase().indexOf(this.search.toLowerCase()) > -1;
				});
				if (this.taggable && this.search.length && !this.optionExists(this.search)) {
					options.unshift(this.search);
				}
				return options;
			},
			isValueEmpty () {
				if (this.mutableValue) {
					if (typeof this.mutableValue === 'object') {
						return !Object.keys(this.mutableValue).length;
					}
					return !this.mutableValue.length;
				}
				return true;
			},
			valueAsArray () {
				if (!this.mutableValue) return [];
				if (this.multiple) {
					return this.mutableValue;
				} else if (this.mutableValue) {
					return [this.mutableValue];
				}
				return [];
			}
		}
	};
</script>
